package com.sun.common.Realm;

import com.sun.common.BaseContext;
import com.sun.common.Jwt.JwtToken;
import com.sun.entity.User;
import com.sun.service.UserService;
import com.sun.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @Project: word
 * @Author: DengYinzhe
 * @Date: 2023/2/3 17:27
 * @FileName: CommonUserRealm
 * @Description:
 */
@Slf4j
@Service
public class CommonUserRealm extends AuthorizingRealm {


    @Resource
    private JwtUtils jwtUtils;


    @Resource
    private UserService userService;



    /**
     * 大坑！，必须重写此方法，不然Shiro会报错
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }


    /**
     * 只有当检测用户需要权限或者需要判定角色的时候才会走
     * */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("MyRealm doGetAuthorizationInfo() 方法授权 ");
        String username = principals.toString();
        User user = userService.getUserByAccount(username);
        if (StringUtils.isBlank(username)) {
            throw new AuthenticationException("token认证失败");
        }
        //查询当前
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        //查询数据库来获取用户的角色
        info.addRole(String.valueOf(user.getType()));
        //查询数据库来获取用户的权限
        //info.addStringPermission(String.valueOf(user.getType()));
        return info;
    }

    /**
     * 默认使用此方法进行用户名正确与否验证, 如果没有权限注解的话就不会去走上面的方法只会走这个方法
     * 其实就是 过滤器传过来的token 然后进行 验证 authenticationToken.toString() 获取的就是
     * 你的token字符串,然后你在里面做逻辑验证就好了,没通过的话直接抛出异常就可以了
     * */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
        String token = (String) auth.getCredentials();
        String username = jwtUtils.getAccount(token);
        if (username == null) {
            throw new AuthenticationException("token invalid");
        }

        User userBean = userService.getUserByAccount(username);
        if (userBean == null) {
            throw new AuthenticationException("User didn't existed!");
        }

        if (! jwtUtils.verify(token, userBean.getAccount())) {
            throw new AuthenticationException("Username or password error");
        }
        BaseContext.setCurrentId(userBean.getId());
        return new SimpleAuthenticationInfo(username, token, "CommonUserRealm");
    }
}
